import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from python_ai.common.xcommon import sep

pd.set_option('display.max_columns', None,
              'display.expand_frame_repr', False)

sep('Load and shuffle data')
df = pd.read_csv(r'../../../../../large_data/ML2/共享单车/train.csv')
m, n = df.shape
np.random.seed(666)
rand_idx = np.random.permutation(m)
df = df.iloc[rand_idx]
# columns:
# datetime  season  holiday  workingday  weather  temp   atemp  humidity  windspeed  casual  registered  count
# atemp 体感温度？
# casual 未注册用户租赁数
# registered 注册用户租赁数
# count = casual + registered

# 将datetime列，切分出年月日时   YYYY-MM-DD HH:mm:ss
df['Y'] = df['datetime'].map(lambda x: int(x.split(' ')[0].split('-')[0]), 10)
df['M'] = df['datetime'].map(lambda x: int(x.split(' ')[0].split('-')[1]), 10)
df['D'] = df['datetime'].map(lambda x: int(x.split(' ')[0].split('-')[2]), 10)
df['H'] = df['datetime'].map(lambda x: int(x.split(' ')[1].split(':')[0]), 10)
import calendar
import datetime
df['month'] = df['M'].map(lambda x: calendar.month_name[x])
df['day'] = df['datetime'].map(
    lambda x: calendar.day_name[
        datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S').weekday()
    ]
)
print(df[:5])

# figure groups
plt.figure(figsize=[16, 8])
spr = 2
spc = 4
spn = 0

# 按照小时，统计用车数量
spn += 1
ax = plt.subplot(spr, spc, spn)
plt.title('H - count')
sns.barplot(data=df,
            x='H',
            y='count',
            estimator=np.sum,
            ci=None,
            ax=ax
            )


# 最终按照上班高峰，下班高峰，白天低谷，晚上低谷，分成四个小时段
def hour_section(h):
    if h <= 6:
        return 0
    elif h <= 10:
        return 1
    elif h <= 15:
        return 2
    elif h <=20:
        return 3
    else:
        return 4


df['h_sec'] = df['H'].map(hour_section)
spn += 1
ax = plt.subplot(spr, spc, spn)
plt.title('H sections - count')
sns.barplot(data=df,
            x='h_sec',
            y='count',
            estimator=np.sum,
            ci=None,
            ax=ax
            )

spn += 1
ax = plt.subplot(spr, spc, spn)
plt.title('count box')
sns.boxplot(data=df,
            y='count',
            ax=ax)

# 显示非噪音数据的比例
sep('显示非噪音数据的比例')
mu = df['count'].mean()
sigma = df['count'].std()
idx_noise = abs(df['count'] - mu) > 3 * sigma
idx_good = np.invert(idx_noise)
print(f'非噪音数据的比例:{idx_good.sum()/len(idx_good):.4f}')

# 删除噪音数据（保留非噪音数据）
sep('删除噪音数据（保留非噪音数据）')
df = df[idx_good]
idx_noise2 = abs(df['count'] - mu) > 3 * sigma
idx_good2 = np.invert(idx_noise2)
print(f'非噪音数据的比例:{idx_good2.sum()/len(idx_good2):.4f}')

# ③	从数据中获取'temp', 'atemp', 'humidity', 'windspeed'列作为特征（5分）
x = df[['temp', 'atemp', 'humidity', 'windspeed']]


# ④	从数据中获取'count'作为标签值（5分）
y = df['count']

# ⑥	使用皮尔逊系数绘制热图（5分）
xcorr = x.corr()
spn += 1
ax = plt.subplot(spr, spc, spn)
sns.heatmap(xcorr, ax=ax, annot=True)
top, bottom = ax.get_ylim()
ax.set_ylim(top + 0.5, bottom - 0.5)

# ⑦	将皮尔逊系数大于1特征进行处理（删除1项）（5分）
sep('⑦	将皮尔逊系数大于1特征进行处理（删除1项）（5分）')
print(df.columns)
df.drop(labels='atemp', axis=1, inplace=True)
print(df.columns)

# ⑧	使用留出法切分数据，比例7:3（5分）
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.7, random_state=666)

# (2)	模型处理及评估（35分）

# ①	创建管道，内部填写后续三项内容（5分）
# ②	管道中先进行多项式处理，使用3次方（5分）
# ③	管道中进行标准化处理（5分）
# ④	管道中使用线性回归（5分）
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.linear_model import LinearRegression
pipe = Pipeline([
    ['poly', PolynomialFeatures(degree=3)],
    ['std', StandardScaler()],
    ['lin_reg', LinearRegression()]
])

# ⑤	拟合训练集数据（5分）
pipe.fit(x_train, y_train)
print(f'Training score = {pipe.score(x_train, y_train)}')
print(f'Testing score = {pipe.score(x_test, y_test)}')

# ⑥	打印预测值（5分）
h_test = pipe.predict(x_test)
spn += 1
ax = plt.subplot(spr, spc, spn)
plt.scatter(y_test, y_test, color='b', s=1)
plt.scatter(y_test, h_test, color='y', s=1, zorder=100)

# ⑦	打印输出模型的均方误差（5分）
from sklearn.metrics import mean_squared_error, r2_score
print(f'模型的均方误差: {mean_squared_error(y_test, h_test)}')
print(f'模型的R方得分: {r2_score(y_test, h_test)}')

# Finally show all plotting
plt.show()
